package com.jinbaoty.recyclebins.command;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.jinbaoty.recyclebins.server.OrderForm;
import com.jinbaoty.recyclebins.server.ResponseData;
import com.jinbaoty.recyclebins.utils.HexDump;
import com.jinbaoty.recyclebins.command.UsbPortUtils;
import com.orhanobut.logger.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;

public class CommandTask{


    private UsbSerialPort port;

    private Handler serialStatusHandler;

    private String returnVal;

    private boolean success;

    private CommandParam nowCommand;

    private Double weight=0.0;

    private String weightStr="";

    private Double totalPrice;

    private int waiting = CommandParam.WAITING_NO;

    public static final int WEIGHT_RETURN = 0x7d;

    public static final int FINISH = 0x7c;

    public static final int STOP = 0x7b;

    private OrderForm orderForm;

    private List<Byte> returnValBytes = new ArrayList<>();



    public static double jzNumber=1.000;
    public CommandParam getNowCommand(){
        return this.nowCommand;
    }

    public void setWaiting(int waiting){
        this.waiting = waiting;
    }

    public CommandTask(UsbSerialPort port, Handler serialStatusHandler){
        this.port = port;
        this.serialStatusHandler = serialStatusHandler;
    }

    public void startRecycleTask(OrderForm orderForm){
        UsbPortUtils.setRunning(true);
        returnVal = "";
        CommandParam[] commandParamOrders =null;

        /*JSONObject data = (JSONObject)responseData.getData();
        OrderForm orderForm = JSONObject.parseObject(data.toJSONString(), OrderForm.class);*/
        this.orderForm = orderForm;
        Integer commandSet = orderForm.getCommandSet();
        int orderIndex = (commandSet-1) % CommandOrder.orderSet.length;
        /*if (commandSet.equals(1)) {
            commandParamOrders=  CommandFromService.door1Orders;
            //sendMessage("衣物回收！");
        }else{
            //sendMessage("塑料回收！");
            commandParamOrders = CommandFromService.door2Orders;
        }*/
        commandParamOrders = CommandOrder.orderSet[orderIndex];
        this.orderForm.setErrorMsg("");
        double preWeight = 0.0;
        CommandParam weightCommandParam = null;
        for(CommandParam commandParam:commandParamOrders){
            if(commandParam.getCommandTag().startsWith("weight")){
                weightCommandParam = commandParam;
                if(port!=null) {
                    Logger.d("串口写操作："+commandParam.getCommandName()+"："+ HexDump.toHexString(commandParam.getCommandVal()));
                    try {
                        int write = port.write(new byte[]{commandParam.getCommandVal()}, 400);
                        byte buffer[] = startReadData(commandParam);
                        int readLen = buffer.length;
                        String weightStr  = new String(buffer,0,readLen);
                        Logger.d("回收返回："+weightStr);
                        weightStr = weightStr.replaceAll("[^0-9.]", "");
                        if(NumberUtil.isDouble(weightStr)) {

                            preWeight = Double.parseDouble(weightStr)*jzNumber;
                            Logger.d("读取原始重量："+preWeight*jzNumber);
                            success = true;
                        }else{
                            sendMessage("回收操作失败：" + commandParam.getErrorMsg() + "，请联系管理员。");
                            Log.d("回收操作失败", "");
                            this.orderForm.setErrorMsg(this.orderForm.getErrorMsg()+commandParam.getErrorMsg());
                            this.orderForm.setState(new Long(STOP));
                            sendMessage(this.orderForm,STOP);
                            return;
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    //sendMessage("发送指令："+commandParam.getCommandVal());
                }
                break;
            }
        }

        for(CommandParam commandParam:commandParamOrders){
            try {
                this.nowCommand = commandParam;

                if(commandParam.getCommandVal()==CommandParam.WAITING_TAG){
                    this.waiting = CommandParam.WAITING_LOOP;
                    sendMessage(this,CommandParam.WAITING_TAG);
                    while(this.waiting==CommandParam.WAITING_LOOP){

                        Logger.d("串口456操作："+commandParamOrders[4].getCommandName()+"："+ HexDump.toHexString(commandParamOrders[4].getCommandVal()));

                        try {
                            int write = port.write(new byte[]{commandParamOrders[4].getCommandVal()}, 400);
                            byte buffer[] = startReadData(commandParamOrders[4]);
                            int readLen = buffer.length;
                            String weightStr  = new String(buffer,0,readLen);
                            Logger.d("回收返回："+weightStr);
                            weightStr = weightStr.replaceAll("[^0-9.]", "");
                            if(NumberUtil.isDouble(weightStr)) {
                                this.weight = (Double.parseDouble(weightStr)-preWeight)*jzNumber;
                                this.weight = this.weight>=0?this.weight:0.0;
                                long wasteWeight = Math.round(this.weight * 1000);
                                if(wasteWeight>0){
                                    this.returnVal = NumberUtil.roundStr(this.weight,3);
                                    this.weightStr = this.returnVal;
                                }
                                sendMessage("回收物重量：" + NumberUtil.roundStr(this.weight,3),WEIGHT_RETURN);

                            }else{
                                sendMessage("回收操作失败：" + commandParam.getErrorMsg() + "，请联系管理员。");
                                Log.d("回收操作失败", "");
                                this.orderForm.setErrorMsg(this.orderForm.getErrorMsg()+commandParam.getErrorMsg());
                                this.orderForm.setState(new Long(STOP));
                                sendMessage(this.orderForm,STOP);
                                return;
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                    }
                    if(this.waiting==CommandParam.WAITING_END) {
                        this.orderForm.setErrorMsg("用户取消");
                        this.orderForm.setState(new Long(STOP));

                        break;
                    }

                }else {
                    if(port!=null) {
                        Logger.d("串口写操作："+commandParam.getCommandName()+"："+ HexDump.toHexString(commandParam.getCommandVal()));
                        int write = port.write(new byte[]{commandParam.getCommandVal()}, 400);

                        //sendMessage("发送指令："+commandParam.getCommandVal());
                    }
                    success = true;
                    returnVal = "";
                    Logger.d("串口读操作："+commandParam.getCommandName()+",超时："+commandParam.getReadTimeout());
                    byte buffer[] = startReadData(commandParam);
                    int readLen = buffer.length;
                    if (commandParam.getReturnType() != CommandParam.RETURN_VOID) {
                        if(readLen>0){
                            if(nowCommand.getCommandTag().equals("weight")){//称重
                                String weightStr  = new String(buffer,0,readLen);
                                this.returnVal = weightStr;
                                this.weightStr = weightStr;
                                weightStr = weightStr.replaceAll("[^0-9.]", "");
                                if(NumberUtil.isDouble(weightStr)) {
                                    this.weight = (Double.parseDouble(weightStr)-preWeight)*jzNumber;
                                    this.weight = this.weight>=0?this.weight:0.0;
                                    long wasteWeight = Math.round(this.weight * 1000);
                                    if(wasteWeight>0){
                                        this.returnVal = NumberUtil.roundStr(this.weight,3);
                                        this.weightStr = this.returnVal;
                                    }
                                    this.orderForm.setWasteWeight(wasteWeight);
                                   // sendMessage("回收物重量：" + this.returnVal);

                                    this.orderForm.setTotalPrice(Math.round((Double.parseDouble(weightStr))*1000*jzNumber));
                                    sendMessage(this.orderForm, WEIGHT_RETURN);
                                    success = true;
                                }else{
                                    success = false;
                                }
                            }else{
                                this.returnVal = new String(buffer,0,readLen);
                            }
                            success = true;

                        }else{
                            Logger.d("串口读操作：没有读取到任何内容");
                            success =false;
                        }
                        if (commandParam.getReturnType() == CommandParam.RETURN_FORCE) {
                            if (!success) {
                                sendMessage("回收操作失败：" + commandParam.getErrorMsg() + "，请联系管理员。");
                                Log.d("回收操作失败", "");
                                this.orderForm.setErrorMsg(this.orderForm.getErrorMsg()+commandParam.getErrorMsg());
                                this.orderForm.setState(new Long(STOP));
                                break;
                            } else {
                                String result = this.returnVal.replaceAll("(;+)$","");
                                String successVal = commandParam.getSuccessVal();
                                if (StrUtil.isBlank(successVal) || StrUtil.containsAnyIgnoreCase(result, successVal)) {
                                    if(StrUtil.isNotBlank(commandParam.getSuccessMsg())) {
                                        sendMessage(commandParam.getSuccessMsg());
                                    }
                                } else {
                                    success = false;
                                    Log.d("回收操作失败", "");
                                    this.orderForm.setErrorMsg(this.orderForm.getErrorMsg()+"，回收箱指令（"+commandParam.getCommandName()+"）要求返回：（"+successVal+"），实际返回：（"+result+"）。");
                                    this.orderForm.setState(new Long(STOP));
                                    sendMessage("回收操作失败：" + commandParam.getErrorMsg() + "，请联系管理员。");
                                    break;
                                }
                            }
                        }
                    }
                    if (success) {
                        if (StrUtil.isNotBlank(commandParam.getSuccessMsg()))
                            sendMessage(commandParam.getSuccessMsg());
                    }
                    if (commandParam.getWriteGap() > 0) {
                        try {
                            Thread.sleep(commandParam.getWriteGap());
                            Logger.d("清除串口缓存");
                            port.read(new byte[50],400);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(success) {
            if(!new Long(STOP).equals(this.orderForm.getState())){
                this.orderForm.setState(new Long(FINISH));
                if(isNeedWeight(commandParamOrders)) {
                    if (StrUtil.isBlank(this.weightStr)) {
                        this.weightStr = "0000.000";
                    } else {
                        String replace = this.weightStr.replace(";", "");
                        if (NumberUtil.isDouble(replace)) {
                            this.weightStr = replace;
                        } else {
                            this.weightStr = "0000.000";
                        }
                    }
                    this.weightStr = this.weight != null ? NumberUtil.roundStr(this.weight,3) : this.weightStr;
                 //   sendMessage("本次回收，回收物重量：" + this.weightStr + " ，获得等值环保积分。");
                }else{

                }
            }else {

            }

        }else{



            this.orderForm.setState(new Long(STOP));
        }

        sendMessage(this.orderForm,FINISH);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(port!=null) {
            Logger.d("串口写操作："+commandParamOrders[3].getCommandName()+"："+ HexDump.toHexString(commandParamOrders[3].getCommandVal()));
            try {
                int write = port.write(new byte[]{commandParamOrders[3].getCommandVal()}, 400);
            } catch (IOException e) {
                e.printStackTrace();
            }

            //sendMessage("发送指令："+commandParam.getCommandVal());
        }
       // sendMessage("本次回收结束，感谢您对环保的支持!");
        UsbPortUtils.setRunning(false);
    }



    public void sendMessage(Object obj){
        Log.d("串口状态消息",obj.toString());
        Message msg= new Message();
        msg.obj = obj;
        serialStatusHandler.sendMessage(msg);
    }
    public void sendMessage(Object obj,int which){
        Log.d("串口状态消息",obj.toString());
        Message msg = new Message();
        msg.obj = obj;
        msg.what = which;
        serialStatusHandler.sendMessage(msg);
    }

    private boolean isNeedWeight(CommandParam[] orders){
        for(CommandParam param:orders){
            if (param.getCommandTag().equals("weight")) {
                return true;
            }
        }
        return false;

    }
    private byte[] startReadData2(CommandParam commandParam) throws IOException {
        byte buffer[] = new byte[50];
        long beginTime = System.currentTimeMillis();
        int readLen =0;
        List<Byte> returnVals = new ArrayList<>();
        for(int repeat=0;repeat<commandParam.getReadRepeat();repeat++) {
            this.orderForm.setErrorMsg(this.orderForm.getErrorMsg()+"【第"+(repeat+1)+"次读：《"+commandParam.getCommandName()+"，"+HexDump.toHexString(commandParam.getCommandVal())+"，"+commandParam.getReadRepeat()+"，"+commandParam.getWriteRepeat()+"》：");
            do {
                readLen = port.read(buffer, commandParam.getReadTimeout());
                String readVal = null;
                if (readLen > 0) {
                    String temp = "";
                    for (int i = 0; i < readLen; i++) {
                        String byteHexString = HexDump.toHexString(buffer[i]);
                        String byteChar = new String(new byte[]{buffer[i]});
                        temp += byteHexString + "(" + byteChar + ");";
                        this.orderForm.setErrorMsg(this.orderForm.getErrorMsg() + "《" + byteHexString + "（" + byteChar + "）》");
                        returnVals.add(buffer[i]);
                    }

                    readVal = new String(buffer, 0, readLen);
                    Logger.d("第"+(repeat+1)+"次读：串口获取到的内容：" + temp + "^^^^^" + readVal);
                }
                if(StrUtil.endWith(readVal,";")) break;
            } while (System.currentTimeMillis() - beginTime < commandParam.getReadTimeout());
            String endReadVal = "";
            if (returnVals.size() > 0) {
                readLen = returnVals.size();
                buffer = new byte[returnVals.size()];
                for (int i = 0; i < returnVals.size(); i++) {
                    buffer[i] = returnVals.get(i);
                }
                endReadVal = new String(buffer, 0, readLen);
                Logger.d("第"+(repeat+1)+"次读：串口最终读取结果：" + endReadVal);
            }
            this.orderForm.setErrorMsg(this.orderForm.getErrorMsg() + " ≡≡《" + endReadVal + "》" + "】");
            if(CommandParam.RETURN_FORCE==commandParam.getReturnType() && !StrUtil.endWith(endReadVal,";")){
                if(repeat>0 && commandParam.getWriteRepeat()+1-repeat>0){
                    int write = port.write(new byte[]{commandParam.getCommandVal()}, 400);
                    returnVals.clear();
                    continue;
                }
            }else{
                if("weight".equals(commandParam.getCommandTag())){
                    String number = endReadVal.replaceAll("[^0-9.]", "");
                    if (!NumberUtil.isDouble(number)) {
                        int write = port.write(new byte[]{commandParam.getCommandVal()}, 400);
                        returnVals.clear();
                        continue;
                    }
                }
                break;
            }
        }
        return buffer;
    }

    private byte[] startReadData(CommandParam commandParam) throws IOException {
        byte buffer[] = new byte[500];
        long beginTime = System.currentTimeMillis();
        int readLen =0;
        List<Byte> returnVals = new ArrayList<>();
        String orderFormRecycleLog = "";
        String portLog = "";
        portLog+="发送指令：《"+commandParam.getCommandName()+"，"+HexDump.toHexString(commandParam.getCommandVal())+"，读次数："+commandParam.getReadRepeat()+"，写次数："+commandParam.getWriteRepeat()+"》";
        orderFormRecycleLog+=portLog;
        int repeatMax = commandParam.getReadRepeat()<3?3:commandParam.getReadRepeat();
        for(int repeat=0;repeat<repeatMax;repeat++) {
            orderFormRecycleLog+=("【第"+(repeat+1)+"次读：");
            portLog+=("【第"+(repeat+1)+"次读：");
            do {
                readLen = port.read(buffer, commandParam.getReadTimeout());
                String readVal = null;

                if (readLen > 0) {
                    String temp = "";
                    for (int i = 0; i < readLen; i++) {
                        temp += HexDump.toHexString(buffer[i]) + "(" + new String(new byte[]{buffer[i]})+ ");";
                        orderFormRecycleLog+=( "《" + HexDump.toHexString(buffer[i]) + "（" + new String(new byte[]{buffer[i]}) + "）》");
                        returnVals.add(buffer[i]);
                    }

                    readVal = new String(buffer, 0, readLen);
                    portLog+="《"+temp+"》";
                }
                if(StrUtil.endWith(readVal,";")) break;
            } while (System.currentTimeMillis() - beginTime < commandParam.getReadTimeout());
            String endReadVal = "";
            if (returnVals.size() > 0) {
                readLen = returnVals.size();
                buffer = new byte[returnVals.size()];
                for (int i = 0; i < returnVals.size(); i++) {
                    buffer[i] = returnVals.get(i);
                }
                endReadVal = new String(buffer, 0, readLen);
                portLog+=("，最终读取结果：" + endReadVal+"】=> ");
            }else{
                portLog+="《空》】=> ";
            }
            orderFormRecycleLog+=( " ≡≡《" + endReadVal + "》" + "】");
            if(CommandParam.RETURN_FORCE==commandParam.getReturnType() && !StrUtil.endWith(endReadVal,";")){
                if(repeat>0 && commandParam.getWriteRepeat()+1-repeat>0){
                    int write = port.write(new byte[]{commandParam.getCommandVal()}, 400);
                    returnVals.clear();
                    continue;
                }
            }else{
                if("weight".equals(commandParam.getCommandTag())){
                    String number = endReadVal.replaceAll("[^0-9.]", "");
                    if (!NumberUtil.isDouble(number)) {
                        int write = port.write(new byte[]{commandParam.getCommandVal()}, 400);
                        returnVals.clear();
                        continue;
                    }
                }
                break;
            }
        }
        //Logger.d(TAG+"："+portLog);
        Logger.d(StrUtil.removeSuffix(portLog,"=> ")+"\n");
        this.orderForm.setErrorMsg(this.orderForm.getErrorMsg()+orderFormRecycleLog);
        return buffer;
    }
}
